﻿using BZ.Logger;
using NDK.Module.BLL;
using NDK.Module.Model;
using NDK.Motion.BLL;
using NDK.Motion.MachineManager;
using NDK.Motion.Monitor;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.ComponentModel;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace NDK.Module.StationLogic
{
    [Monitor(Description = "扫码工位")]
    public class LoadingMove : StationLogic
    {
        #region 通用
        //记录当前步骤，用于步骤变化的比较
        private StationStep _curStep = StationStep.开始准备;
        //对外提供工位的步骤变化事件
        public override event PropertyChangedEventHandler PropertyChanged;
        //对外提供唯一实例
        public static LoadingMove Instance = new LoadingMove();
        //私有化的构造函数
        private LoadingMove () : base()
        {
            this.Name = "扫码";
        }
        //步骤字段、属性
        private StationStep _step = StationStep.开始准备;
        [Monitor(Description = "当前步骤")]
        public StationStep Step
        {
            get
            {
                return _step;
            }
            set
            {
                if(_curStep != value)
                {
                    _step = value;
                    _curStep = value;

                    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(value.ToString()));
                }
            }
        }
        #endregion

        #region 变量

        public event Common.delegateUpdateStartOnce UpdateStartOnceEvent;

        string BarcodeTemp1 = "Test";
        string BarcodeTemp2 = "Test";
        int ProductID1 = 0;
        int ProductID2 = 0;

        int PutCount = 0; //放料计数
        bool IsGrrPick;  // GRR反向取料
        #endregion

        /// <summary>
        /// 工站初始化
        /// </summary>
        public override void Init ()
        {
            base.Init();
            Step = StationStep.开始准备;
            logBaseInfo = "LoadingMove";

            IsGrrPick = false;
            PutCount = 0; //放料计数
            ProductID1 = 0;
            ProductID2 = 0;

            DataQueue1 = new ConcurrentQueue<MeasureProduct>();
            DataQueue2 = new ConcurrentQueue<MeasureProduct>();
        }

        private bool VacuumOn ()
        {
            return VacuumMethod(true, (Machine.do_扫码平台真空1吸, Machine.di_扫码平台真空1反馈, !Common.屏蔽治具1), (Machine.do_扫码平台真空2吸, Machine.di_扫码平台真空2反馈, !Common.屏蔽治具2));
        }

        public void VacummOff ()
        {
            Machine.do_扫码平台真空1吸.OFF();
            Machine.do_扫码平台真空2吸.OFF();
            Machine.do_扫码平台真空1破.ON();
            Machine.do_扫码平台真空2破.ON();
            Thread.Sleep(100);
            Machine.do_扫码平台真空1破.OFF();
            Machine.do_扫码平台真空2破.OFF();
        }
        /// <summary>
        /// 工站动作流程
        /// </summary>
        /// <param name="mode"></param>
        public override void ActionProcess ()
        {
            try
            {
                var s1 = Common.dic_plcComm_Bool["stPLC_PC.bSafety_LDRbt"];//判断机械手是否处于安全位  true,危险位置 false,安全位置
                switch(Step)
                {
                    case StationStep.开始准备:
                        PutCount = 0;
                        Step = StationStep.流程开始;
                        break;

                    case StationStep.流程开始:
                        if(Common.isWriteLog)
                        {
                            logCtStr = string.Empty;
                            swStepTime.Restart();
                            swStationCT.Restart();
                            logCtStr += $"{logBaseInfo},工站开始,{swStepTime.ElapsedMilliseconds},{Environment.NewLine}";
                            Common.sw3.Restart();
                        }
                        Step = StationStep.轴初始位;
                        break;

                    case StationStep.轴初始位:
                        if(MotionControl.AxesMove(Machine.pos_Load_初始位))
                        {
                            PLCWriteMethod(logBaseInfo, ("stPC_PLC.Spare_Bool[3]", !Machine.di_扫码平台真空1反馈.GetStatus(), null));
                            PLCWriteMethod(logBaseInfo, ("stPC_PLC.Spare_Bool[4]", !Machine.di_扫码平台真空2反馈.GetStatus(), null));

                            if(IsGrrPick)
                            {
                                Step = StationStep.屏蔽判断;
                                break;
                            }
                            Step = StationStep.模式判断;
                        }
                        break;

                    case StationStep.模式判断:
                        if(Common.Line != "MUR")
                        {
                            if(Common.点检启动一次 && !Common.pointCheckEnd)
                            {
                                Common.点检启动一次 = false;
                                Common.pointCheck = true;
                                Common.Cur点检次数++;
                                if(Common.Cur点检次数 >= 1)
                                {
                                    Common.pointCheckEnd = true;
                                }
                                Step = StationStep.脱机真空;
                                break;
                            }
                        }
                        else
                        {
                            if(Common.GRR循环模式)
                            {
                                if(Common.启动一次 || !Common.GRREnd)
                                {
                                    Common.启动一次 = false;
                                    Common.CurGRR循环次数++;
                                    UpdateStartOnceEvent.BeginInvoke(Common.启动一次, $"[{Common.CurGRR循环次数}/{Common.GRR循环次数}]", null, null);
                                    Common.GRREnd = Common.CurGRR循环次数 >= Common.GRR循环次数;
                                    if(Common.GRREnd && Common.GRR换穴 == 0)
                                    {
                                        Common.GRR换穴 = 1;
                                        Common.GRREnd = false;
                                        Common.CurGRR循环次数 = 0;
                                    }
                                    if(Common.手动启动)
                                    {
                                        Step = StationStep.脱机真空;
                                    }
                                    else if(Common.是否联机上料PLC)
                                    {
                                        //Machine.do_扫码平台真空1吸.ON();//执行GRR前判断平台是否有料
                                        //Machine.do_扫码平台真空2吸.ON();
                                        //Thread.Sleep(500);
                                        //PLCWriteMethod(logBaseInfo, ("stPC_PLC.Spare_Bool[3]", !Machine.di_扫码平台真空1反馈.GetStatus(), null));
                                        //PLCWriteMethod(logBaseInfo, ("stPC_PLC.Spare_Bool[4]", !Machine.di_扫码平台真空2反馈.GetStatus(), null));
                                        //Machine.do_扫码平台真空1吸.OFF();
                                        //Machine.do_扫码平台真空2吸.OFF();
                                        Step = StationStep.屏蔽判断;
                                    }
                                }
                            }
                            else
                            {
                                if(Common.手动启动 && Common.启动一次)
                                {
                                    Common.启动一次 = false;
                                    UpdateStartOnceEvent.BeginInvoke(Common.启动一次, "", null, null);
                                    Step = StationStep.脱机真空;
                                }
                                else if(Common.是否联机上料PLC)
                                {
                                    Step = StationStep.屏蔽判断;
                                }
                            }
                        }
                        break;

                    case StationStep.脱机真空:
                        if(VacuumOn())
                        {
                            Step = StationStep.轴扫码位;
                        }
                        break;

                    case StationStep.屏蔽判断:
                        PutCount = Common.屏蔽治具1 ? 1 : 0;
                        Step = StationStep.允许放料;
                        break;

                    case StationStep.允许放料:
                        ret_Plc = Common.dic_plcComm_Bool[$"stPLC_PC.bPut_Comp[{PutCount}]"];
                        if(!ret_Plc && !Common.dic_plcComm_Bool[$"stPLC_PC.bPut_InPos[{PutCount}]"])
                        {
                            isOK = PLCWriteMethod(logBaseInfo, ($"stPC_PLC.bPut_Req[{PutCount}]", true, null));
                            if(!isOK)
                                break;
                            Common.AppendUiLog.Log($"扫描工位已发送允许{PutCount + 1}放料信号", LogType.Info);
                            Step = StationStep.等待放料;
                        }
                        break;

                    case StationStep.等待放料:
                        ret_Plc = Common.dic_plcComm_Bool[$"stPLC_PC.bPut_InPos[{PutCount}]"];
                        if(!ret_Plc)
                            break;
                        Common.AppendUiLog.Log($"扫描工位已收到放料到位{PutCount + 1}信号", LogType.Info);
                        Step = StationStep.打开真空;
                        break;

                    case StationStep.打开真空:
                        if(IsGrrPick)
                        {
                            if(PutCount == 0)
                            {
                                Machine.do_扫码平台真空1吸.OFF();
                                Machine.do_扫码平台真空1破.ON();
                                Thread.Sleep(200);
                                Machine.do_扫码平台真空1破.OFF();
                            }
                            else
                            {

                                Machine.do_扫码平台真空2吸.OFF();
                                Machine.do_扫码平台真空2破.ON();
                                Thread.Sleep(200);
                                Machine.do_扫码平台真空2破.OFF();
                            }
                        }
                        else
                        {
                            isOK = PutCount == 0 ? VacuumMethod(true, (Machine.do_扫码平台真空1吸, Machine.di_扫码平台真空1反馈, !Common.屏蔽治具1)) :
                                                   VacuumMethod(true, (Machine.do_扫码平台真空2吸, Machine.di_扫码平台真空2反馈, !Common.屏蔽治具2));

                            if(!isOK)
                                break;
                        }
                        Step = StationStep.允许离开;
                        break;

                    case StationStep.允许离开:
                        isOK = PLCWriteMethod(logBaseInfo, ($"stPC_PLC.bPut_LeaveAllow[{PutCount}]", true, null));
                        if(!isOK)
                            break;
                        Common.AppendUiLog.Log($"扫描工位已发送允许{PutCount + 1}离开信号", LogType.Info);
                        Step = StationStep.等待离开;
                        break;

                    case StationStep.等待离开:
                        ret_Plc = Common.dic_plcComm_Bool[$"stPLC_PC.bPut_Comp[{PutCount}]"];
                        if(!ret_Plc)

                            break;
                        isOK = PLCWriteMethod("Tray盘定位", ($"stPC_PLC.bPut_LeaveAllow[{PutCount}]", false, null),
                                                           ($"stPC_PLC.bPut_Req[{PutCount}]", false, null));
                        Common.AppendUiLog.Log($"扫描工位已收到离开{PutCount + 1}完成信号", LogType.Info);
                        Step = StationStep.次数判断;
                        break;

                    case StationStep.次数判断:
                        if(PutCount == 0)
                        {
                            if(Common.屏蔽治具2)
                            {
                                if(IsGrrPick)
                                {
                                    IsGrrPick = false;
                                    Step = StationStep.轴初始位;
                                    break;
                                }
                                Step = StationStep.轴扫码位;
                            }
                            else
                            {
                                PutCount++;
                                Step = StationStep.允许放料;
                            }
                        }
                        else
                        {
                            PutCount = 0;
                            if(IsGrrPick)
                            {
                                IsGrrPick = false;
                                Step = StationStep.轴初始位;
                                break;
                            }
                            Step = StationStep.轴扫码位;
                        }
                        break;

                    case StationStep.轴扫码位:
                        if(!Common.手动启动 && !s1)
                            break;
                        axRes = MotionControl.AxesMove(Machine.pos_Load_扫码位);
                        if(!axRes)
                            break;
                        Step = StationStep.等待下工位开要料;
                        break;

                    case StationStep.等待下工位开要料:
                        if(LoadingTrans1.Instance.工位要料)
                        {
                            Step = StationStep.触发扫码;
                        }
                        break;

                    case StationStep.触发扫码:
                        var IsDone = ScanMethod();
                        if(!IsDone.Item2)
                            break;
                        BarcodeTemp1 = IsDone.Item1[0];
                        BarcodeTemp2 = IsDone.Item1[1];
                        string[] sn = new string[2] { IsDone.Item1[0], IsDone.Item1[1] };

                        Transform.Instance.SNQueue.Enqueue(sn);
                        MeasureStation.Instance.SNQueue.Enqueue(sn);

                        ProductID1++;
                        ProductID2 = Common.Line == "MUR" ? ProductID1 + 1 : ProductID2 + 1;
                        DataQueue1.Enqueue(new MeasureProduct() { SN = BarcodeTemp1, whichBlock = Common.whichBlock, Position = "0", ProductID = ProductID1 });
                        DataQueue2.Enqueue(new MeasureProduct() { SN = BarcodeTemp2, whichBlock = Common.whichBlock, Position = "1", ProductID = ProductID1 });
                        Step = StationStep.轴接料位;
                        break;

                    case StationStep.轴接料位:
                        if(MotionControl.AxesMove(Machine.pos_Load_接料位))
                        {
                            工位完成 = true;
                            Step = StationStep.等待下工位关要料;
                        }
                        break;

                    case StationStep.等待下工位关要料:
                        if(!LoadingTrans1.Instance.工位要料)
                        {
                            工位完成 = false;
                            Step = StationStep.判断模式;
                        }
                        break;

                    case StationStep.判断模式:
                        if((!Common.GRR循环模式 || Common.GRREnd) && !Common.pointCheck)
                        {
                            Step = StationStep.流程结束;
                        }
                        else
                        {
                            base.GRR工位要料 = true;
                            Step = StationStep.GRR等待下工位开完成;
                        }
                        break;

                    case StationStep.GRR等待下工位开完成:
                        if(LoadingTrans1.Instance.GRR工位完成)
                        {
                            LoadingTrans1.Instance.VacuumOff();
                            Step = StationStep.GRR打开真空;
                        }
                        break;

                    case StationStep.GRR打开真空:
                        if(VacuumOn())
                        {
                            GRR工位要料 = false;
                            Step = StationStep.等待下工站关完成;
                        }
                        break;

                    case StationStep.等待下工站关完成:
                        if(!LoadingTrans1.Instance.GRR工位完成)
                        {
                            IsGrrPick = true;
                            Step = StationStep.流程结束;
                        }
                        break;

                    case StationStep.流程结束:
                        Common.sw3.Stop();
                        if(Common.isWriteLog)
                        {
                            logCtStr += $"{logBaseInfo},扫码工位结束,{swStepTime.ElapsedMilliseconds},{Environment.NewLine}";
                            logCtStr += $"{logBaseInfo},扫码工位结束,{swStationCT.ElapsedMilliseconds},{Environment.NewLine}";
                            PublicMethod.WriteLogToTxt(logCtStr, $"000StepCT_{DateTime.Now.ToString("yyyyMMdd")}", "3.LoadingMove");
                        }
                        Step = StationStep.开始准备;
                        break;
                }
            }
            catch(Exception ex)
            {
                UILog_Error($"[ LoadingMove ActionProcess Thread ERROR] {ex.Message}");
            }
        }

        public override void EmptyActionProcess ()
        {
            ActionProcess();
        }

        public override void GRRActionProcess ()
        {
            ActionProcess();
        }


        /// <summary>
        /// 工位步骤定义
        /// </summary>
        public enum StationStep
        {
            开始准备,
            流程开始,
            轴初始位,
            模式判断,
            脱机真空,
            屏蔽判断,
            允许放料,
            等待放料,
            打开真空,
            允许离开,
            等待离开,
            次数判断,

            轴扫码位,
            触发扫码,
            等待下工位开要料,
            轴接料位,
            等待下工位关要料,
            判断模式,

            GRR工站要料,
            GRR等待下工位开完成,
            GRR打开真空,
            等待下工站关完成,

            流程结束,
        }

        public (List<string>, bool) ScanMethod ()
        {
            List<string> str = new List<string> { DateTime.Now.ToString("yyyyMMddHHmmss_1"), DateTime.Now.ToString("yyyyMMddHHmmss_2") };
            if(!Common.是否带料 || Common.屏蔽扫码)
                return (str, true);
            if(Common.pointCheck)
            {
                str.ForEach(x => x += "Block");
                return (str, true);
            }
            try
            {
                List<Task<(int, string)>> tasks = new List<Task<(int, string)>>();
                if(!Common.屏蔽治具1)
                {
                    tasks.Add(Task.Run(() => (0, Common.ScanReader1.TrigReader(2000))));
                }
                if(!Common.屏蔽治具2)
                {
                    tasks.Add(Task.Run(() => (1, Common.ScanReader2.TrigReader(2000))));
                }
                Task.WaitAll(tasks.ToArray());
                var task = tasks.FindAll(x => x.Result.Item2 == "");
                if(task.Count > 0)
                {
                    string mes = string.Empty;
                    task.ForEach(x => mes += $"扫码{x.Result.Item1 + 1} ");
                    if(AlarmPause("扫码报警", $"{mes}异常，请检查", "调整扫码位置", "重新检测", "忽略报警，继续运行") == DialogResult.OK)
                    {
                        return (str, false);
                    }
                    return (str, true);
                }
                else
                {
                    tasks.ForEach(x => str[x.Result.Item1] = x.Result.Item2.Trim());
                    return (str, true);
                }
            }
            catch
            {
                if(AlarmPause("扫码报警", $"扫码枪异常，请检查", "尝试重新链接扫码枪", "重新检测", "忽略报警，继续运行") == DialogResult.OK)
                {
                    return (str, false);
                }
                return (str, true);
            }
        }
    }
}
